package org.mbds.wolf.android.hce.seservice;

import java.io.File;
import java.util.HashMap;

import org.mbds.wolf.android.tools.FileUtilities;
import org.mbds.wolf.exception.WolfException;
import org.mbds.wolf.seql.APDUCommand;
import org.mbds.wolf.seql.APDUModel;
import org.mbds.wolf.seql.AppletModel;
import org.mbds.wolf.seql.SeqlMetadata;
import org.mbds.wolf.tools.BytesTool;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.cardemulation.HostApduService;
import android.os.Bundle;
import android.util.Log;


/**
 * 
 * @author alesas
 *
 */
public class WolfHceService extends HostApduService 
{
	
	public final static String TAG = "WolfHceService";
	
	public final static String DEFAULT_CONFIG_FILE_NAME = "config.xml";
	
	public final static String ACTION_MSG_COMMAND_APDU		= "org.mbds.wolf.android.hce.seservice.CAPDU";
	public final static String ACTION_MSG_RESPONSE_APDU 	= "org.mbds.wolf.android.hce.seservice.RAPDU";
	
    public final static String KEY_COMMAND_APDU = "cmdApdu";
    public final static String KEY_RESPONSE_APDU = "respApdu";
	
	private static HashMap<String, WolfApplet> currentApplets = new HashMap<String, WolfApplet>();
	private WolfApplet selectedApplet = null;
	private AppletModel model = null;
	private File configFile = null;
	private SeqlMetadata metadata = null;
	private static WolfHceService currentInstance = null;
	private BroadcastReceiver receiver;

	
	/**
	 * WolfHceReceiver:
	 * This class is intended to receive APDU instructions to be processed
	 */
	public static class WolfHceReceiver extends BroadcastReceiver 
	{

		@Override
		public void onReceive(Context context, Intent intent) 
		{
			if (currentInstance==null)
			{
				new WolfHceService();
			}
	    	if (intent != null && intent.getAction().equals(ACTION_MSG_COMMAND_APDU))
	    	{
	    		Bundle extras = intent.getExtras();
	    		if (extras != null) 
	    		{
					byte[] apduResponse = APDUModel.SW_GENERAL_ERROR;
	    			try
	    			{
	    			 byte[] cmdApdu = extras.getByteArray(KEY_COMMAND_APDU);
	    			 apduResponse = currentInstance.processCommandApdu(cmdApdu, extras);
	    			} 
	    			catch (Exception e)
	    			{
	    				//
	    			}
	    			 extras.putByteArray(KEY_RESPONSE_APDU, apduResponse);
	    			 intent.setAction(ACTION_MSG_RESPONSE_APDU);
	    			 intent.putExtras(extras);
	    			 currentInstance.sendBroadcast(intent);
	    		}
		    }

		}
	};
	
	/**
	 * Constructor
	 */
	public WolfHceService()
	{
		super();
		currentInstance = this;
	}

	@Override
	public void onCreate()
	{
		receiver = new WolfHceReceiver();
		IntentFilter filter = new IntentFilter(WolfHceService.ACTION_MSG_COMMAND_APDU);
		registerReceiver(receiver, filter);
	}
	
	/**
	 * loadApplet
	 * @param aID
	 * @return WolfApplet
	 */
	private WolfApplet loadApplet(String aID) 
	{
		try 
		{
			if (configFile==null || metadata==null)
			{
				configFile = FileUtilities.getFileFromAssets(this, DEFAULT_CONFIG_FILE_NAME);
				metadata = SeqlMetadata.getInstance(configFile);
			}
			model = metadata.getAppletByAID(aID);
			WolfApplet w = new WolfApplet(model, this);
			putApplet(aID, w);
			return w;
		} 
		catch (Exception e1) 
		{
			e1.printStackTrace();
		}
		return null;
	}	
	
	/**
	 * putApplet
	 * @param aID
	 * @param applet
	 * @return boolean
	 */ 
	private static synchronized boolean putApplet(String aID, WolfApplet applet) 
	{
		if (getApplet(aID)==null) 
		{
			currentApplets.put(aID, applet);
			return true;
		}
		return false;	
	}
	

	/**
	 * getApplet
	 * @param aID
	 * @return WolfApplet
	 */
	private static WolfApplet getApplet(final String aID) 
	{
		return currentApplets.get(aID);
	}
	
	
	/**
	 * Overrides inherited onDestry method
	 */
	@Override
	public void onDestroy() 
	{
		unregisterReceiver(receiver);
		selectedApplet = null;
		currentInstance = null;
		super.onDestroy();
	}
	
	/**
	 * Implementation of inherited HCE abstract method
	 */
	@Override
	public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) 
	{
		byte[] apduResponse = APDUModel.SW_GENERAL_ERROR;
		
		if (APDUModel.isCommandSelect(commandApdu)) 
		{
			try 
			{
				APDUCommand cmd = new APDUCommand(commandApdu);
				String aID = BytesTool.byteArrayToHexString(cmd.getData()).replaceAll(" ", "");
				Log.d(TAG, " Try to select AID: " + aID);
				selectedApplet = getApplet(aID);
				if (selectedApplet==null) 
				{
					selectedApplet = loadApplet(aID);
				}
			} 
			catch (WolfException e) 
			{
				e.printStackTrace();
			}
		}
		if (selectedApplet!=null)
		{
			apduResponse = selectedApplet.processCommandApdu(commandApdu, extras);
			return apduResponse;
		}
		return apduResponse;
	}
	

	
	/**
	 * Implementation of inherited HCE abstract method
	 */
	@Override
	public void onDeactivated(int reason) 
	{
		selectedApplet = null;
		String reasonStr="UNKNOWN";
		switch (reason) 
		{
			case DEACTIVATION_DESELECTED:
				reasonStr="DEACTIVATION_DESELECTED";
				break;
			case DEACTIVATION_LINK_LOSS:
				reasonStr="DEACTIVATION_LINK_LOSS";
				break;
		}
		Log.i(TAG, "Deactivated: " + reasonStr);
	}

}
